import QtQuick 1.0
/***************************************************************************************************
*Importing the custom components from the Shapes lib(MultiTouchItem,Ellipse defined in main.cpp).  *
***************************************************************************************************/
import Shapes 1.0

Ellipse {
    id: kolobok
    /***********************************************************************************************
    *Taking focus to receive key events.                                                           *
    ***********************************************************************************************/
    focus: true

    /***********************************************************************************************
    *The items horizonal speed.                                                                    *
    ***********************************************************************************************/
    property int horizontalSpeed: 0
    /***********************************************************************************************
    *The items vertical speed.                                                                     *
    ***********************************************************************************************/
    property int verticalSpeed: 0
    /***********************************************************************************************
    *Flag indicating if the left key is pressed.                                                   *
    ***********************************************************************************************/
    property bool leftPressed: false
    /***********************************************************************************************
    *Flag indicating if the right key is pressed.                                                  *
    ***********************************************************************************************/
    property bool rightPressed: false
    /***********************************************************************************************
    *Flag indicating if the up key is pressed.                                                     *
    ***********************************************************************************************/
    property bool upPressed: false
    /***********************************************************************************************
    *Flag indicating if the item can react to the up key being pressed.                            *
    ***********************************************************************************************/
    property bool blockUpPress: false
    /***********************************************************************************************
    *The items horizontal direction.                                                               *
    ***********************************************************************************************/
    property int horizontalDirection : 0

    margin: 5
    width: 100; height: 100
    objectName: "kolobok"
    x: 0; y: 0; z: 0

    /***********************************************************************************************
    *Connecting arrow pressed/released signal to the key pressed/released handler.                 *
    ***********************************************************************************************/
    Connections {
        target: arrow_left
        onPressed: keyPressed(Qt.Key_Left);
        onReleased: keyReleased(Qt.Key_Left);
    }

    Connections {
        target: arrow_right
        onPressed: keyPressed(Qt.Key_Right);
        onReleased: keyReleased(Qt.Key_Right);
    }

    Connections {
        target: arrow_up
        onReleased: keyReleased(Qt.Key_Up);
        onPressed: keyPressed(Qt.Key_Up);
    }
    /**********************************************************************************************/

    /***********************************************************************************************
    *The Characters image.                                                                         *
    ***********************************************************************************************/
    Image {
        id: kolobok_image
        objectName: "kolobok_image"
        x: 0; y: 0
        width: 100; height: 100
        source: LevelController.face
        smooth: true
        opacity: 1.0
    }

    /***********************************************************************************************
    *A timer triggering the doMovement function every 25ms.                                        *
    ***********************************************************************************************/
    Timer {
        id: timer
        interval: 25; running: false; repeat: true
        onTriggered: doMovement()
    }

    /***********************************************************************************************
    *Key pressed/released signals triggering pressed/released handlers.                            *
    ***********************************************************************************************/
    Keys.onPressed: {
        if (event.isAutoRepeat)
            return;
        keyPressed(event.key);
    }

    Keys.onReleased: {
        if (event.isAutoRepeat)
            return;
        keyReleased(event.key);
    }
    /**********************************************************************************************/

    /***********************************************************************************************
    *The Key pressed handler.                                                                      *
    ***********************************************************************************************/
    function keyPressed(key) {
        /*******************************************************************************************
        *Ensure the timer is running.                                                              *
        *******************************************************************************************/
        timer.running = true;
        if (key == Qt.Key_Left) {
            /***************************************************************************************
            *set the leftPressed flag to true                                                      *
            *if horizontal direction = 0 set horizontal direction to -1                            *
            ***************************************************************************************/
            leftPressed = true;
            if (horizontalDirection == 0)
                horizontalDirection = -1;
        } else if (key == Qt.Key_Right) {
            /***************************************************************************************
            *set the rightPressed flag to true                                                     *
            *if horizontal direction = 0 set horizontal direction to 1                             *
            ***************************************************************************************/
            rightPressed = true;
            if (horizontalDirection == 0)
                horizontalDirection = 1;
        } else if (key == Qt.Key_Up && !blockUpPress) {
            /***************************************************************************************
            *If up not blocked set the upPressed flag to true.                                     *
            ***************************************************************************************/
            upPressed = true;
        }
        doMovement();
    }

    /***********************************************************************************************
    *The Key released handler.                                                                     *
    ***********************************************************************************************/
    function keyReleased(key) {
        /*******************************************************************************************
        *Ensure the timer is running.                                                              *
        *******************************************************************************************/
        timer.running = true;
        if (key == Qt.Key_Left) {
            /***************************************************************************************
            *set the leftPressed flag to false                                                     *
            *if rightPressed set horizontal direction to 1                                         *
            ***************************************************************************************/
            leftPressed = false;
            if (rightPressed)
                horizontalDirection = 1;
            else
                horizontalDirection = 0;
        } else if (key == Qt.Key_Right) {
            /***************************************************************************************
            *set the rightPressed flag to false                                                    *
            *if leftPressed set horizontal direction to -1                                         *
            ***************************************************************************************/
            rightPressed = false;
            if (leftPressed)
                horizontalDirection = -1;
            else
                horizontalDirection = 0;
        } else if (key == Qt.Key_Up) {
            /***************************************************************************************
            *Set the upPressed flag to true.                                                       *
            ***************************************************************************************/
            upPressed = false;
        }
        doMovement();
    }

    /***********************************************************************************************
    *The movement function.                                                                        *
    ***********************************************************************************************/
    function doMovement() {
        /*******************************************************************************************
        *Fix opacity.                                                                              *
        *******************************************************************************************/
        if (opacity < 1.0)
            opacity += 0.01;
        /*******************************************************************************************
        *Character out of bounds, reset position, reset scene scroll, stop the timer and return.   *
        *******************************************************************************************/
        if ( y > 1000) {
            x = kolobokStartX;
            y = kolobokStartY;
            timer.running = false;
            resetScrollScene();
            return;
        }

        /*******************************************************************************************
        *Adjusting horizontal speed.                                                               *
        *******************************************************************************************/
        if (horizontalDirection > 0) {
            /***************************************************************************************
            *If moving right and speed less than 10, increase speed.                               *
            ***************************************************************************************/
            if (horizontalSpeed < 10) {
                ++horizontalSpeed;
            }
        } else if (horizontalDirection < 0) {
            /***************************************************************************************
            *If moving left and speed higher than -10, decrease speed.                             *
            ***************************************************************************************/
            if (horizontalSpeed > -10) {
                --horizontalSpeed;
            }
        } else {
            /***************************************************************************************
            *No movement key pressed and speed not 0, bring speed to 0.                            *
            ***************************************************************************************/
            if (horizontalSpeed < 0)
                ++horizontalSpeed;
            else if (horizontalSpeed > 0)
                --horizontalSpeed;
        }

        /*******************************************************************************************
        *Adjusting vertical speed.                                                                 *
        *******************************************************************************************/
        if (upPressed) {
            /***************************************************************************************
            *If up pressed set vertical speed to -20, set upPressed to false                       *
            *block up key event handling                                                           *
            ***************************************************************************************/
            verticalSpeed = -20;
            upPressed = false;
            blockUpPress = true;
        } else {
            /***************************************************************************************
            *If up not pressed increase vertical speed.                                            *
            ***************************************************************************************/
            if (verticalSpeed == -1)
                ++verticalSpeed;
            ++verticalSpeed;
        }

        /*******************************************************************************************
        *Change position                                                                           *
        *******************************************************************************************/
        if (verticalSpeed) {
            /***************************************************************************************
            *If verticalSpeed != 0 change items y position.                                        *
            ***************************************************************************************/
            y += verticalSpeed;
        }
        if (horizontalSpeed) {
            /***************************************************************************************
            *If horizontalSpeed != 0 change items x position.                                      *
            *Rotate the characters image in the appropriate direction.                             *
            ***************************************************************************************/
            x += horizontalSpeed;
            kolobok_image.rotation = (kolobok_image.rotation + horizontalSpeed) % 360
        }

        var centerX = width/2;
        var centerY = height/2;

        var collided = false;
        /*******************************************************************************************
        *Get the list of colliding items.                                                          *
        *******************************************************************************************/
        var list = Level.collidingItems(kolobok);
        var iteration = 0;
        /*******************************************************************************************
        *Run 4 times at most.                                                                      *
        *******************************************************************************************/
        while (iteration < 5) {

            if (list.length == 0)
                /***********************************************************************************
                *No collisions.                                                                    *
                ***********************************************************************************/
                break;

            /***************************************************************************************
            *Calculate the global position of the items center.                                    *
            ***************************************************************************************/
            var globalCenterX = x + centerX;
            var globalCenterY = y + centerY;

            var i = -1;
            var i1 = 0;

            while ( i1 < list.length) {
                if (list[i1].objectName == "cactus") {
                    /*******************************************************************************
                    *Collided  with cactus, play groan, drop burn flag, reduce opacity.            *
                    *******************************************************************************/
                    Level.playGroan();
                    burn = false;
                    if (opacity > 0.2)
                        opacity -= 0.1;
                } else if (list[i1].objectName == "fire" ) {
                    /*******************************************************************************
                    *Collided  with fire, play groan, set burn flag, reduce opacity.               *
                    *Remove the flame object form the list and continue loop.                      *
                    *******************************************************************************/
                    Level.playGroan();
                    burn = true;
                    if (opacity > 0.2)
                        opacity -= 0.1;
                    list.splice(i1,1);
                    continue;
                }

                if (list.length > 1 && globalCenterY < list[i1].y - 20 ) {
                    /*******************************************************************************
                    *Collision on bottom                                                           *
                    *******************************************************************************/
                    if (globalCenterX >= list[i1].x && globalCenterX < list[i1].x + list[i1].width) {
                        /***************************************************************************
                        *Collision on bottom-center                                                *
                        ***************************************************************************/
                        if ( i != -1) {
                            /***********************************************************************
                            *If not the first bottom collision, remove colliding item form list    *
                            *and decrement i1 to start at the right index in the next iteration.   *
                            ***********************************************************************/
                            list.splice(i,1);
                            --i1;
                        }
                        i = i1;
                    } else if ( i == -1 ) {
                        i = i1;
                    }
                }
                ++i1;
            }
            i = 0;

            /***************************************************************************************
            *Get the first intersection rectangle.                                                 *
            ***************************************************************************************/
            var rect = Level.intersected(kolobok,list[i]);
            var intersectX = rect.x + rect.width/2;
            var intersectY = rect.y + rect.height/2;
            if ( !intersectX && !intersectY) {
                /***********************************************************************************
                *If no intersection, remove item from the list and continue loop.                  *
                ***********************************************************************************/
                list.splice(i,1);
                ++iteration;
                continue;
            }

            if (centerY < intersectY && Math.abs(centerX-intersectX) < 10) {
                /***********************************************************************************
                *Collision on bottom-center.                                                       *
                *Drop the blockUpPress flag, adjust y position.                                    *
                *Reduce and invert vertical speed.                                                 *
                ***********************************************************************************/
                blockUpPress = false;
                y -= Math.max(rect.height,1);
                verticalSpeed *= -0.5;
                if ( Math.abs(verticalSpeed) > 1)
                    /*******************************************************************************
                    *Mark collision only if the vertical speed is big enough.                      *
                    *To prevent the boing sound from playing when the bounce is to small.          *
                    *******************************************************************************/
                    collided = true;
            } else if (centerY > intersectY && Math.abs(centerX-intersectX) < 10) {
                /***********************************************************************************
                *Collision on top-center                                                           *
                *Drop the blockUpPress flag, adjust y position.                                    *
                *Reduce and invert vertical speed.                                                 *
                *Mark collision.                                                                   *
                ***********************************************************************************/
                blockUpPress = false;
                y += Math.max(rect.height,1);
                verticalSpeed *= -0.5;
                collided = true;
            } else if (centerX < intersectX && Math.abs(centerY-intersectY) < 15) {
                /***********************************************************************************
                *Collision on right-mid                                                            *
                *Adjust x position.                                                                *
                *Reduce and invert horizontal speed.                                               *
                *Mark collision.                                                                   *
                ***********************************************************************************/
                x -= Math.max(rect.width,1);
                horizontalSpeed *= -0.75;
                collided = true;

            } else if (centerX > intersectX && Math.abs(centerY-intersectY) < 15 ) {
                /***********************************************************************************
                *Collision on left-mid                                                             *
                *Adjust x position.                                                                *
                *Reduce and invert horizontal speed.                                               *
                *Mark collision.                                                                   *
                ***********************************************************************************/
                x += Math.max(rect.width,1);
                horizontalSpeed *= -0.75;
                collided = true;
            } else {
                /***********************************************************************************
                *Collision on corner                                                               *
                *Reduce and invert vertical speed.                                                 *
                *Reduce and invert horizontal speed.                                               *
                *Mark collision.                                                                   *
                ***********************************************************************************/
                verticalSpeed *= -0.75;
                horizontalSpeed *= -0.75;
                collided = true;

                if (centerX > intersectX) {
                    if (centerY > intersectY ) {
                        /***************************************************************************
                        *Collision on top-left                                                     *
                        *Adjust y position.                                                        *
                        ***************************************************************************/
                        y += Math.max(rect.height,1);
                    } else  {
                        /***************************************************************************
                        *Collision on bottom-left                                                  *
                        *Drop the blockUpPress flag, adjust y position.                            *
                        ***************************************************************************/
                        y -= Math.max(rect.height,1);
                        blockUpPress = false;
                    }
                } else {
                    if (centerY > intersectY ) {
                        /***************************************************************************
                        *Collision on top-right                                                    *
                        *Adjust y position.                                                        *
                        ***************************************************************************/
                        y += Math.max(rect.height,1);
                    } else  {
                        /***************************************************************************
                        *Collision on bottom-right                                                 *
                        *Drop the blockUpPress flag, adjust y position.                            *
                        ***************************************************************************/
                        y -= Math.max(rect.height,1);
                        blockUpPress = false;
                    }
                }

                /***********************************************************************************
                *If horizontal speed = 0, set appropriate horizontal speed.                        *
                *Adjust x position.                                                                *
                ***********************************************************************************/
                if( horizontalSpeed == 0) {
                    if (centerX > intersectX)
                        horizontalSpeed += 1;
                    else
                        horizontalSpeed -= 1;
                }
                x += horizontalSpeed;
            }


            if (list.length == 1)
                break;
            /***************************************************************************************
            *Get the list of colliding items.                                                      *
            ***************************************************************************************/
            list = Level.collidingItems(kolobok);
            ++iteration;
        }

        /*******************************************************************************************
        *If collided play the boing sound.                                                         *
        *******************************************************************************************/
        if (collided == true)
            Level.playBoing();

        /*******************************************************************************************
        *Stop timer if no movement.                                                                *
        *******************************************************************************************/
        if ( !verticalSpeed && !horizontalSpeed && horizontalDirection == 0 && opacity == 1.0) {
            timer.running = false;
        }

        var dx = 0;
        /*******************************************************************************************
        *Check if the scene needs to be and can be translated.                                     *
        *******************************************************************************************/
        if ( x > -screen_transl.x + 1066 && -screen_transl.x < Level.columnCount*100 - 1600 )
            dx = x - (-screen_transl.x) - 1066;
        else if (x < -screen_transl.x + 533 && -screen_transl.x > 0)
            dx = x - (-screen_transl.x) - 533;

        /*******************************************************************************************
        *Translate scene by dx.                                                                    *
        *******************************************************************************************/
        scrollScene(dx);
    }

    /***********************************************************************************************
    *Falldown function, called to start the game.                                                  *
    ***********************************************************************************************/
    function fallDown()
    {
        /*******************************************************************************************
        *Start timer, set vertical speed to 1 and call the movement function.                      *
        *******************************************************************************************/
        timer.running = true;
        verticalSpeed = 1;
        doMovement();
    }
}
